package com.bihua.wx.service.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bihua.common.core.domain.PageQuery;
import com.bihua.common.core.page.TableDataInfo;
import com.bihua.common.utils.StringUtils;
import com.bihua.wx.domain.WxMsgTemplate;
import com.bihua.wx.domain.WxTemplateMsgLog;
import com.bihua.wx.domain.bo.TemplateMsgBatchBo;
import com.bihua.wx.domain.bo.WxMsgTemplateBo;
import com.bihua.wx.domain.bo.WxUserBo;
import com.bihua.wx.domain.vo.WxMsgTemplateVo;
import com.bihua.wx.domain.vo.WxUserVo;
import com.bihua.wx.mapper.WxMsgTemplateMapper;
import com.bihua.wx.mapper.WxTemplateMsgLogMapper;
import com.bihua.wx.service.IWxMsgTemplateService;
import com.bihua.wx.service.IWxUserService;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplate;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;

/**
 * 消息模板Service业务层处理
 *
 * @author bihua
 * @date 2023-05-22
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class WxMsgTemplateServiceImpl implements IWxMsgTemplateService {

    private final WxMsgTemplateMapper baseMapper;

    private final WxMpService wxService;

    private final IWxUserService iWxUserService;
    private final WxTemplateMsgLogMapper wxTemplateMsgLogMapper;

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 默认批次提交数量
     */
    int DEFAULT_BATCH_SIZE = 1000;
    /**
     * 查询消息模板
     */
    @Override
    public WxMsgTemplateVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询消息模板列表
     */
    @Override
    public TableDataInfo<WxMsgTemplateVo> queryPageList(WxMsgTemplateBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<WxMsgTemplate> lqw = buildQueryWrapper(bo);
        Page<WxMsgTemplateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询消息模板列表
     */
    @Override
    public List<WxMsgTemplateVo> queryList(WxMsgTemplateBo bo) {
        LambdaQueryWrapper<WxMsgTemplate> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<WxMsgTemplate> buildQueryWrapper(WxMsgTemplateBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<WxMsgTemplate> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getAppid()), WxMsgTemplate::getAppid, bo.getAppid());
        lqw.eq(StringUtils.isNotBlank(bo.getTemplateId()), WxMsgTemplate::getTemplateId, bo.getTemplateId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), WxMsgTemplate::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getTitle()), WxMsgTemplate::getTitle, bo.getTitle());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), WxMsgTemplate::getContent, bo.getContent());
        lqw.eq(StringUtils.isNotBlank(bo.getUrl()), WxMsgTemplate::getUrl, bo.getUrl());
        lqw.eq(bo.getStatus() != null, WxMsgTemplate::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增消息模板
     */
    @Override
    public Boolean insertByBo(WxMsgTemplateBo bo) {
        WxMsgTemplate add = BeanUtil.toBean(bo, WxMsgTemplate.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改消息模板
     */
    @Override
    public Boolean updateByBo(WxMsgTemplateBo bo) {
        WxMsgTemplate update = BeanUtil.toBean(bo, WxMsgTemplate.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(WxMsgTemplate entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除消息模板
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public void syncWxTemplate(String appid) throws WxErrorException {
        wxService.switchoverTo(appid);
        List<WxMpTemplate> wxMpTemplateList= wxService.getTemplateMsgService().getAllPrivateTemplate();
        List<WxMsgTemplate> templates = wxMpTemplateList.stream().map(item->new WxMsgTemplate(item,appid)).collect(Collectors.toList());
        baseMapper.insertOrUpdateBatch(templates, DEFAULT_BATCH_SIZE);
    }

    @Override
    @Async
    public void sendMsgBatch(TemplateMsgBatchBo bo, String appid) {
        log.info("批量发送模板消息任务开始,参数：{}",bo.toString());
        wxService.switchover(appid);
        WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder()
            .templateId(bo.getTemplateId())
            .url(bo.getUrl())
            .miniProgram(bo.getMiniprogram())
            .data(bo.getData());
        int currentPage=1;
        long totalPages=Integer.MAX_VALUE;
        WxUserBo wxUserBo = bo.getWxUserFilterParams();
        wxUserBo.setAppid(appid);
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageSize(500);
        while (currentPage<=totalPages){
            pageQuery.setPageNum(currentPage);
            //按条件查询用户
            TableDataInfo<WxUserVo> wxUsers = iWxUserService.queryPageList(wxUserBo, pageQuery);
            log.info("批量发送模板消息任务,使用查询条件，处理第{}页，总用户数：{}",currentPage, wxUsers.getTotal());
            wxUsers.getRows().forEach(user->{
                WxMpTemplateMessage msg = builder.toUser(user.getOpenid()).build();
                this.sendTemplateMsg(msg,appid);
            });
            currentPage++;
            totalPages=getTotalPages(pageQuery.getPageSize(), wxUsers.getTotal());
        }
        log.info("批量发送模板消息任务结束");
    }
    /**
     * 当前分页总页数
     */
    private long getTotalPages(Integer pageSize, long total) {
        if (pageSize == 0) {
            return 0L;
        }
        long pages = total / pageSize;
        if (total % pageSize != 0) {
            pages++;
        }
        return pages;
    }
    /**
     * 发送微信模版消息,使用固定线程的线程池
     */
    @Override
    @Async
    public void sendTemplateMsg(WxMpTemplateMessage msg,String appid) {
        threadPoolTaskExecutor.submit(() -> {
            String result;
            try {
                wxService.switchover(appid);
                result = wxService.getTemplateMsgService().sendTemplateMsg(msg);
            } catch (WxErrorException e) {
                result = e.getMessage();
            }

            //保存发送日志
            WxTemplateMsgLog log = new WxTemplateMsgLog(msg,appid, result);
            wxTemplateMsgLogMapper.insert(log);
        });
    }
}
